
/*
 Initial code taken from : Quodlibet.be
 */
package org.iabako.server.tools.pdftable;

import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;

import java.awt.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class PdfTable {
    private float nextYpos;
    private float margin;
    private PDPage page;
    private PDPageContentStream contentStream;
    private List<PDOutlineItem> bookmarks;
    private float verticalCellMargin = 5f;
    private float horizontalCellMargin = 5f;
    protected Color lineColor;
    protected float lineWidth;
    protected float tableWidth;


    public PdfTable(float yPos, float margin, PDPage page, PDPageContentStream contentStream) {
        this.nextYpos = yPos;
        this.margin = margin;
        this.page = page;
        this.contentStream = contentStream;
    }

    public PdfTable(PdfWriterHelper pdfWriterHelper) {
        this.nextYpos = pdfWriterHelper.top;
        this.margin = pdfWriterHelper.margin;
        this.page = pdfWriterHelper.page;
        this.contentStream = pdfWriterHelper.pageContentStream;
    }

    public void drawRow(PdfRow row) throws IOException {
        //draw the horizontal line
        tableWidth = row.getWidth();
        float nexty = nextYpos;
        contentStream.setLineWidth(lineWidth);
        contentStream.setStrokingColor(lineColor);

        if (!row.isNoLine()) {
            contentStream.drawLine(margin, nexty, margin + row.getWidth(), nexty);
        }

        //draw the bookmark
        if (row.getBookmark() != null) {
            PDPageXYZDestination bookmarkDestination = new PDPageXYZDestination();
            bookmarkDestination.setPage(page);
            bookmarkDestination.setTop((int) nextYpos);
            row.getBookmark().setDestination(bookmarkDestination);
            this.addBookmark(row.getBookmark());
        }

        //draw the vertical lines
        float nextx = margin;
        for (PdfCell cell : row.getCells()) {
            //Fill Cell Color
            if (cell.getFillColor() != null) {
                contentStream.setNonStrokingColor(cell.getFillColor());
                //y start is bottom pos
                contentStream.fillRect(nextx, nexty - row.getHeight(horizontalCellMargin, verticalCellMargin), cell.getWidth(), row.getHeight(horizontalCellMargin, verticalCellMargin));

                contentStream.closeSubPath();
            }

            if (row.getCells().indexOf(cell) == 0 || !cell.isNoLine()) {
                contentStream.drawLine(nextx, nexty, nextx, nexty - row.getHeight(horizontalCellMargin, verticalCellMargin));
            }
            contentStream.closeSubPath();

            nextx += cell.getWidth();
        }
        //draw the line at the right of the table
        contentStream.drawLine(nextx, nexty, nextx, nexty - row.getHeight(horizontalCellMargin, verticalCellMargin));
        contentStream.closeSubPath();

        //now add the cell content
        float cellOffset = margin;
        nextx = margin + horizontalCellMargin;
        nexty = nextYpos - verticalCellMargin * 2;
        for (PdfCell cell : row.getCells()) {

            contentStream.setFont(cell.getFont(), cell.getFontSize());
            if (cell.getTextColor() != null) {
                contentStream.setNonStrokingColor(cell.getTextColor());
            } else {
                contentStream.setNonStrokingColor(Color.BLACK);
            }
            contentStream.beginText();


            int numLines = cell.getParagraph(horizontalCellMargin).getLines().size();
            contentStream.appendRawCommands(cell.getParagraph(horizontalCellMargin).getFontHeight() + " TL\n");

            boolean firstLine = true;
            for (String line : cell.getParagraph(horizontalCellMargin).getLines()) {
                if (line.startsWith("_small_text_")) {
                    line = line.substring("_small_text_".length());
                    contentStream.setFont(cell.getFont(), 6);
                }
                float textWidth = cell.getFont().getStringWidth(line) / 1000 * cell.getFontSize();

                if (cell.isRightAlign()) {
                    nextx = cellOffset + (cell.getWidth() - textWidth - horizontalCellMargin);
                }
                if (firstLine) {
                    firstLine = false;
                    contentStream.moveTextPositionByAmount(nextx, nexty);
                }

                contentStream.drawString(line.trim());
                if (numLines > 0) {
                    contentStream.appendRawCommands("T*\n");
                }
                numLines--;
            }

            contentStream.endText();
            contentStream.closeSubPath();
            nextx += cell.getWidth();
            cellOffset += cell.getWidth();
        }
        //Set Y position for next row
        nextYpos = nextYpos - row.getHeight(horizontalCellMargin, verticalCellMargin);
    }

    public void endTable() throws IOException {
        //Draw line at bottom
        contentStream.drawLine(margin, nextYpos, margin + tableWidth, nextYpos);
        contentStream.closeSubPath();
    }

    public float getNextYpos() {
        return nextYpos;
    }

    private void addBookmark(PDOutlineItem bookmark) {
        if (bookmarks == null) bookmarks = new ArrayList();
        bookmarks.add(bookmark);
    }

    public List<PDOutlineItem> getBookmarks() {
        return bookmarks;
    }

    public Color getLineColor() {
        return lineColor;
    }

    public void setLineColor(Color lineColor) {
        this.lineColor = lineColor;
    }

    public float getLineWidth() {
        return lineWidth;
    }

    public void setLineWidth(float lineWidth) {
        this.lineWidth = lineWidth;
    }

    public void setVerticalCellMargin(float verticalCellMargin) {
        this.verticalCellMargin = verticalCellMargin;
    }

    public void setHorizontalCellMargin(float horizontalCellMargin) {
        this.horizontalCellMargin = horizontalCellMargin;
    }
}
